# -*- coding: utf-8 -*-
#    MythMobile, a Django interface to MythTV for mobile devices
#    Copyright (C) 2011 Andrew Wilkinson (andrewjwilkinson@gmail.com)
#
#     This program is free software; you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation; either version 2 of the License, or
#     (at your option) any later version.
#
#     This program is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#     GNU General Public License for more details.
#
#     You should have received a copy of the GNU General Public License along
#     with this program; if not, write to the Free Software Foundation, Inc.,
#     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

import datetime
import logging
import socket
import time
import threading

from asyncproc import Process

class Connection(object):
    MONITOR = "Monitor"
    PLAYBACK = "Playback"

    NO_EVENTS = "0"
    ALL_EVENTS = "1"
    NO_SYSTEM_EVENTS = "2"
    ONLY_SYSTEM_EVENTS = "3"

    REQUEST_BLOCK = "REQUEST_BLOCK"

    def __init__(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect(("192.168.0.12", 6543))

        self.lock = threading.Lock()

        self.file_transfer_mode = False

        proto_version = self.send_cmd("MYTH_PROTO_VERSION", "63", "3875641D")

        assert proto_version[0] == "ACCEPT", "Incompatible MythTV version - %s" % (proto_version[1], )

    def __del__(self):
        if not self.file_transfer_mode:
            self.send_cmd("DONE")
        self.sock.close()

    def ann(self, client_type=PLAYBACK, hostname=None, events=ALL_EVENTS):
        if hostname is None:
            hostname = socket.gethostname()

        return self.send_cmd("ANN", client_type, hostname, events)[0] == "OK"

    def ann_filetransfer(self, filename, hostname=None, storage_group="Default"):
        if hostname is None:
            hostname = socket.gethostname()

        self.file_transfer_mode = True
        return self.send_cmd("ANN", "FileTransfer", hostname, ["0", filename, storage_group])[1]

    def get_next_free_recorder(self):
        return self.send_cmd(["GET_NEXT_FREE_RECORDER", "-1"])[0]

    def get_chain_id(self):
        return "mythmobile-%s-%s" % (socket.gethostname(), datetime.datetime.now().isoformat())

    def query_recorder_spawn_livetv(self, recorder_id, chain_id, pip, start_channel_num):
        return self.query_recorder(recorder_id, "SPAWN_LIVETV", chain_id, "1" if pip else "0", str(start_channel_num))[0].upper() == "OK"

    def query_recorder_is_recording(self, recorder_id):
        return self.query_recorder(recorder_id, "IS_RECORDING")[0] == "1"

    def query_recorder_get_current_recording(self, recorder_id):
        return self.query_recorder(recorder_id, "GET_CURRENT_RECORDING")

    def query_recorder(self, recorder_id, subcommand, *args):
        return self.send_cmd("QUERY_RECORDER", [recorder_id, subcommand] + list(args))

    def query_filetransfer(self, socket_id, request_type, buf_size):
        return self.send_cmd("QUERY_FILETRANSFER", [socket_id, request_type, str(buf_size)])

    def backend_message_recordinglist_change_add(self, channel_id, start_time=None):
        if start_time is None:
            start_time = datetime.datetime.now()

        return self.backend_message("RECORDING_LIST_CHANGE", "ADD", str(channel_id), [start_time.isoformat().split(".")[0], "empty"])

    def backend_message_livetv_chain_update(self, chain_id):
        return self.backend_message("LIVETV_CHAIN", "UPDATE", [chain_id, "empty"])

    def backend_message(self, subcommand, *args):
        return self.send_cmd(["MESSAGE", subcommand], *args)

    def handle_backend_msg(self, *args):
        pass

    def send_cmd(self, *args):
        self.lock.acquire()
        try:
            data = []

            for arg in args:
                if isinstance(arg, (list, tuple)):
                    data.append("[]:[]".join(arg))
                else:
                    data.append(arg)

            data = " ".join(data)

            msg_len = str(len(data))

            msg = msg_len + " " * (8 - len(msg_len)) + data

            logging.debug(repr(msg))
            self.sock.sendall(msg)

            while True:
                recv_size = self.sock.recv(8)
                if recv_size == "":
                    return

                recv_size = int(recv_size.strip())

                recv_msg = ""
                while len(recv_msg) < recv_size:
                    recv_msg += self.sock.recv(recv_size - len(recv_msg) )

                msg = recv_msg.split("[]:[]")

                if msg[0] == "BACKEND_MESSAGE":
                    self.handle_backend_msg(*msg)
                else:
                    return msg
        finally:
            self.lock.release()

    def read(self, buf_size):
        self.lock.acquire()
        try:
            return self.sock.recv(buf_size)
        finally:
            self.lock.release()
